package cn.jiedanba.cacert.common.ca.crl;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.cert.CRLReason;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509v2CRLBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import com.alibaba.fastjson.JSON;

import cn.jiedanba.cacert.common.bc.base.BaseSecurity;
import cn.jiedanba.cacert.common.ca.PkiUtil;
import cn.jiedanba.cacert.common.ca.crl.domain.CRL;
import cn.jiedanba.cacert.common.ca.crl.domain.PkiCRLRevoke;
import cn.jiedanba.cacert.common.ca.crl.domain.PkiCRL;
import cn.jiedanba.cacert.common.ca.extension.ExtensionUtil;

public class PkiCRLUtil extends BaseSecurity {

	/**
	 * 创建CRL吊销列表
	 * 
	 * @param crl
	 * @return
	 */
	public static X509CRL createX509v2CRL(PkiCRL crl) {
		try {
			// crl颁发者
			X500Name issuerName = new JcaX509CertificateHolder(crl.getSignCert()).getSubject();

			// crl构建对象
			X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerName, new Date());
			// 吊销证书
			crlBuilder.addCRLEntry(crl.getCertSerial(), crl.getRevokeDate(), crl.getReason());
			// crl数字
			CRLNumber crlNumber = new CRLNumber(crl.getSignCert().getSerialNumber());
			Extension extension = new Extension(Extension.cRLNumber, false, crlNumber.getEncoded());
			crlBuilder.addExtension(extension);
			// 下一次更新时间
			crlBuilder.setNextUpdate(crl.getNextUpdate());
			// 授权秘钥标识符
			Extension authorityKeyIdentifier = ExtensionUtil
					.getAuthorityKeyIdentifierExtension(crl.getSignCert().getPublicKey());
			crlBuilder.addExtension(authorityKeyIdentifier);

			JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(crl.getAlgorithm());
			contentSignerBuilder.setProvider(BC);
			X509CRLHolder crlHolder = crlBuilder.build(contentSignerBuilder.build(crl.getPrivateKey()));
			JcaX509CRLConverter converter = new JcaX509CRLConverter();
			converter.setProvider(BC);

			return converter.getCRL(crlHolder);

		} catch (Exception e) {
			throw new RuntimeException("生成crl错误！", e);
		}

	}

	/**
	 * 创建CRL吊销列表，使用原来的crl
	 * 
	 * @param crl
	 * @return
	 */
	public static X509CRL createX509v2CRLWithOldCrl(PkiCRL crl) {
		try {
			// crl颁发者
			X500Name issuerName = new JcaX509CertificateHolder(crl.getSignCert()).getSubject();

			// crl构建对象
			X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerName, new Date());

			crlBuilder.addCRL(new X509CRLHolder(crl.getCrlEncoding()));
			// 吊销证书
			crlBuilder.addCRLEntry(crl.getCertSerial(), crl.getRevokeDate(), crl.getReason());
			// crl数字
			CRLNumber crlNumber = new CRLNumber(crl.getSignCert().getSerialNumber());
			Extension extension = new Extension(Extension.cRLNumber, false, crlNumber.getEncoded());
			crlBuilder.addExtension(extension);
			// 下一次更新时间
			crlBuilder.setNextUpdate(crl.getNextUpdate());

			// 授权秘钥标识符
			Extension authorityKeyIdentifier = ExtensionUtil
					.getAuthorityKeyIdentifierExtension(crl.getSignCert().getPublicKey());
			crlBuilder.addExtension(authorityKeyIdentifier);

			JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(crl.getAlgorithm());
			contentSignerBuilder.setProvider(BC);
			X509CRLHolder crlHolder = crlBuilder.build(contentSignerBuilder.build(crl.getPrivateKey()));
			JcaX509CRLConverter converter = new JcaX509CRLConverter();
			converter.setProvider(BC);

			return converter.getCRL(crlHolder);
		} catch (Exception e) {
			throw new RuntimeException("生成crl错误！");
		}

	}

	/**
	 * 创建 CRL吊销列表，使用旧的crl，并且不进行证书吊销
	 * 
	 * @param crl
	 * @return
	 */
	public static X509CRL createX509v2CRLWithOldCrlNoRevokeCert(PkiCRL crl) {
		try {
			// crl颁发者
			X500Name issuerName = new JcaX509CertificateHolder(crl.getSignCert()).getSubject();

			// crl构建对象
			X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerName, new Date());

			crlBuilder.addCRL(new X509CRLHolder(crl.getCrlEncoding()));

			// crl数字
			CRLNumber crlNumber = new CRLNumber(crl.getSignCert().getSerialNumber());
			Extension extension = new Extension(Extension.cRLNumber, false, crlNumber.getEncoded());
			crlBuilder.addExtension(extension);
			// 下一次更新时间
			crlBuilder.setNextUpdate(crl.getNextUpdate());

			// 授权秘钥标识符
			Extension authorityKeyIdentifier = ExtensionUtil
					.getAuthorityKeyIdentifierExtension(crl.getSignCert().getPublicKey());
			crlBuilder.addExtension(authorityKeyIdentifier);

			JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(crl.getAlgorithm());
			contentSignerBuilder.setProvider(BC);
			X509CRLHolder crlHolder = crlBuilder.build(contentSignerBuilder.build(crl.getPrivateKey()));
			JcaX509CRLConverter converter = new JcaX509CRLConverter();
			converter.setProvider(BC);
			return converter.getCRL(crlHolder);
		} catch (Exception e) {
			throw new RuntimeException("生成crl错误！");
		}

	}

	/**
	 * 创建空白的crl
	 * 
	 * @param bdate
	 * @param edate
	 * @param privateKey
	 * @param certificate
	 * @return
	 */
	public static X509CRL createX509v2CRLEmpty(PkiCRL crl) {
		try {
			// crl颁发者
			X500Name issuerName = new JcaX509CertificateHolder(crl.getSignCert()).getSubject();

			// crl构建对象
			X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerName, new Date());
			// 授权秘钥标识符
			Extension authorityKeyIdentifier = ExtensionUtil
					.getAuthorityKeyIdentifierExtension(crl.getSignCert().getPublicKey());
			crlBuilder.addExtension(authorityKeyIdentifier);

			// crl数字
			CRLNumber crlNumber = new CRLNumber(crl.getCertSerial());
			Extension extension = new Extension(Extension.cRLNumber, false, crlNumber.getEncoded());
			crlBuilder.addExtension(extension);

			// 下一次更新时间
			crlBuilder.setNextUpdate(crl.getNextUpdate());

			JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(crl.getAlgorithm());
			contentSignerBuilder.setProvider(BC);
			X509CRLHolder crlHolder = crlBuilder.build(contentSignerBuilder.build(crl.getPrivateKey()));
			JcaX509CRLConverter converter = new JcaX509CRLConverter();
			converter.setProvider(BC);
			return converter.getCRL(crlHolder);
		} catch (Exception e) {
			throw new RuntimeException("生成crl错误！", e);
		}

	}

	/**
	 * 加载CRL证书吊销列表文件
	 * 
	 * @param crlFilePath
	 * @return
	 * @throws Exception
	 */
	public static X509CRL loadX509CRL(byte[] crlByte) throws Exception {
		InputStream in = new ByteArrayInputStream(crlByte);
		CertificateFactory cf = CertificateFactory.getInstance("X.509");

		X509CRL crl = (X509CRL) cf.generateCRL(in);
		in.close();
		return crl;
	}

	/**
	 * 验证证书是否在CRL中。
	 * 
	 * @param X509CRL
	 *            crl对象
	 * @param br
	 *            证书序列号
	 * @throws IOException
	 */
	private static X509CRLEntry isRevoked(X509CRL crl, BigInteger sn) throws IOException {
		X509CRLEntry set = crl.getRevokedCertificate(sn);
		if (set != null) {
			return set;
		} else {
			return null;
		}
	}

	/**
	 * 验证证书是否在CRL中。
	 * 
	 * @param X509CRL
	 *            crl对象
	 * @param X509Certificate
	 *            证书对象
	 * @throws IOException
	 */
	public static X509CRLEntry isRevoked(X509CRL crl, X509Certificate cert) throws IOException {
		BigInteger sn = cert.getSerialNumber();
		return isRevoked(crl, sn);
	}

	/**
	 * 统计crl总数
	 * 
	 * @param X509CRL
	 *            crl对象
	 * @throws IOException
	 * 
	 */
	public static int num(X509CRL crl) throws IOException {
		Set<?> set = crl.getRevokedCertificates();
		Iterator<?> it = set.iterator();
		int i = 0;
		while (it.hasNext()) {
			it.next();
			i++;
		}
		return i;
	}

	/**
	 * 读取crl吊销列表
	 * 
	 * @param crl
	 * @return
	 */
	public static CRL readCRL(byte[] crl) {
		try {
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509CRL aCrl = (X509CRL) cf.generateCRL(new ByteArrayInputStream(crl));
			CRL ent = new CRL();
			ent.setIssuerDN(aCrl.getIssuerDN().getName());
			ent.setNextUpdateDate(aCrl.getNextUpdate());
			ent.setThisUpdateDate(aCrl.getThisUpdate());
			ent.setSigAlgName(aCrl.getSigAlgName());
			ent.setSigAlgOID(aCrl.getSigAlgOID());
			ent.setSignature(aCrl.getSignature());
			ent.setCrl(aCrl);

			Set<?> tSet = aCrl.getRevokedCertificates();
			Iterator<?> tIterator = tSet.iterator();
			List<PkiCRLRevoke> revokeList = new ArrayList<>();
			while (tIterator.hasNext()) {
				X509CRLEntry tEntry = (X509CRLEntry) tIterator.next();
				CRLReason reason = tEntry.getRevocationReason();
				PkiCRLRevoke crlRevoke = new PkiCRLRevoke();
				crlRevoke.setReason(reason);
				crlRevoke.setRevokeDate(tEntry.getRevocationDate());
				crlRevoke.setSn(PkiUtil.serialNumberConvertString(tEntry.getSerialNumber()));
				revokeList.add(crlRevoke);
			}
			ent.setRevokeList(revokeList);
			return ent;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	public static void main(String[] args) throws IOException {
		byte[] crlByte = FileUtils
				.readFileToByteArray(new File("C:\\Users\\Administrator\\Desktop\\gsrsaovsslca2018.crl"));
		CRL crl = readCRL(crlByte);
		System.out.println(JSON.toJSONString(crl));

		X509CRLEntry flag = isRevoked(crl.getCrl(), new BigInteger("0083ebe6c524c37601e592a4", 16));
		System.out.println(flag);
	}

}
